# coding: utf-8
'''
Created on 27 avr. 2011

@author: shin
'''

from business.Personnage import Personnage
from business.Competence import Competence

class Activite(object):
    '''
    classe de gestion des actions
    '''

    def __init__(self, elements):
        self._deroulement = {}
        '''
            le déroulement est un dictionnaire de liste de tuple.
            Il permet de connaître l'ordre dans lequel va se dérouler
        les actions.
        Les clefs du dictionnaire sont les moments où les actions doivent
        se derouler : des float.
        
        Une action est un tuple dans lequel on trouve :
            1°) Le nom de celui qui va effectuer l'action,
            2°) Le nom de l'action à effectuer (baffe, bouleDeFeu, soin)
            3°) La cible de l'action
                (None lorsqu'il n'y a pas de cible pour le sort)
        Ex :
        _deroulement[1] : [('Asura',  'tourDeJeu', None)]
        _deroulement[2] : [('Mantas', 'coupEpee', 'Shu'),
                          ('Shu', 'protectionUltime_VS_coupEpee', None) ]
         
        ================
        fonctionnement :
        ================
            
            Le jeu regarde le plus petit élément de la liste _deroulement.keys()
        Cela lui donne une liste de tupleAction.
            Lorsque il y a plusieurs élément dans cette liste, le sort en ai jeté
        et random choisiera qui aura la chance de lancer son sorten premier.
        (=> random non implémenté)
        '''
        self._choice = None
        '''
        liste des noms des cases possibles pour l'action
        ex : ["A1", "A2", "B1", ... ]
        '''
        self._tour = 0
        '''
        ou en est le déroulement du jeu
        '''
        self._competenceActive = False
        '''
        niveau de competenceActive : 0 => normal
                              1 => action a été choisi
        '''
        self._prochaineAction = ""
        '''
        le nom de la prochaine action
            Ex "mouvement"
        '''
        self._elements = elements
        self._damierLink = None
        self._competence = Competence()



    def linkDamier(self, damier):
        self._damierLink = damier
    
    def demandeCompetence(self, personnage, competence):
        '''
        - choisi la méthode privé de la classe correspondant à la compétence
        - défini le personnage selectionné pour la classe
        '''
        if (competence == "Mouvement"):
            return self._demandeMouvement(personnage)
        if (competence == "Tir"):
            return self._demandeTir(personnage)
        if (competence == "Frappe"):
            return self._demandeFrappe(personnage)
        if (competence == "Shadow Bolt"):
            return self._demandeShadowBolt(personnage)
        if (competence == "Seduction"):
            return self._demandeSeduction(personnage)
        if (competence == "Passe son tour"):
            return self._demandePasseTour(competence)
        if (competence == "Soigne"):
            return self._demandeSoin(personnage)
        if (competence == "Brise Genoux"):
            return self._demandeBriseGenoux(personnage)
        if (competence == "Ressucite"):
            return self._demandeRessucite(personnage)
        
        raise Exception("compétence non implémenté")
    
    def prevoitCompetence(self, personnage, caseCible):
        if caseCible not in self._choice: return False
        if self._prochaineAction == "Mouvement":
            return False
        
        resultat = []
        
        if (self._prochaineAction == "Tir"):
            list = self._damierLink.contenu(caseCible)
            if len(list) == 0:
                return False
            else: 
                resultat.append("degats")
                resultat.append(self._elements[list[0]].calculRecoitCoup(
                                    self._competence.degatsTir(personnage),
                                    "Physique" ) )
                return resultat

        if (self._prochaineAction == "Frappe"):
            list = self._damierLink.contenu(caseCible)
            if len(list) == 0:
                return False
            else:
                resultat.append("degats")
                resultat.append(self._elements[list[0]].calculRecoitCoup(
                                    self._competence.degatsFrappe(personnage),
                                    "Physique" ) )
                return resultat
        
        if (self._prochaineAction == "Shadow Bolt"):
            list = self._damierLink.contenu(caseCible)
            if len(list) == 0:
                return False
            else:
                resultat.append("degats")
                resultat.append(self._elements[list[0]].calculRecoitCoup(
                                    self._competence.degatsShadowBolt(personnage),
                                    "Ombre" ) )
                return resultat
        
        if self._prochaineAction == "Seduction":
            list = self._damierLink.contenu(caseCible)
            if len(list) == 0:
                return False
            else:
                resultat.append("Joueur")
                resultat.append(" 20% : " + str(personnage.joueur))
                return resultat

        if self._prochaineAction == "Soigne":
            list = self._damierLink.contenu(caseCible)
            if len(list) == 0:
                return False
            cible = self._elements[list[0]]
            if cible.pointDeVie == 0:
                print "On ne peut soigner les personnages mort"
                return False
            else:
                resultat.append("soins")
                resultat.append(self._competence.calculSoin(personnage, cible) )
                return resultat
        
        if (self._prochaineAction == "Brise Genoux"):
            list = self._damierLink.contenu(caseCible)
            if len(list) == 0:
                return False
            else:
                resultat.append("degats")
                resultat.append(5)
                return resultat
        
        if (self._prochaineAction == "Ressucite"):
            list = self._damierLink.contenu(caseCible)
            if len(list) == 0:
                return False
            cible = self._elements[list[0]]
            if cible.pointDeVie > 0:
                print "On ne peut ressuciter les vivants"
                return False
            else:
                resultat.append("soins")
                resultat.append(1)
                return resultat
        
        raise Exception(self._prochaineAction + " n'est pas implémenté")

    def utiliseCompetence(self, personnage, caseCible):
        ''' 
        réalise l'action
        '''
        if caseCible not in self._choice: return False
        
        
        if (self._prochaineAction == "Mouvement"):
            self._damierLink.place(personnage.nom, caseCible)
            return True
        
        if (self._prochaineAction == "Tir"):
            list = self._damierLink.contenu(caseCible)
            if len(list) == 0:
                return False
            else:
                self._elements[list[0]].recoitCoup(
                        self._competence.degatsTir(personnage),
                        "Physique" )
                return True

        if (self._prochaineAction == "Frappe"):
            list = self._damierLink.contenu(caseCible)
            if len(list) == 0:
                return False
            else:
                self._elements[list[0]].recoitCoup(
                        self._competence.degatsFrappe(personnage),
                        "Physique" )
                return True
        
        if (self._prochaineAction == "Shadow Bolt"):
            list = self._damierLink.contenu(caseCible)
            if len(list) == 0:
                return False
            else:
                self._elements[list[0]].recoitCoup(
                        self._competence.degatsShadowBolt(personnage),
                        "Ombre" )
                return True
        
        if (self._prochaineAction == "Seduction"):
            list = self._damierLink.contenu(caseCible)
            if len(list) == 0:
                return False
            else:
                self._competence.seduction(personnage,
                                           self._elements[list[0]] )
                return True

        if (self._prochaineAction == "Soigne"):
            list = self._damierLink.contenu(caseCible)
            if len(list) == 0:
                return False
            cible = self._elements[list[0]]
            if cible.pointDeVie == 0:
                print "On ne peut soigner les personnages mort"
                return False
            else:
                self._competence.soin(personnage,
                                      cible )
                return True
        
        if (self._prochaineAction == "Brise Genoux"):
            list = self._damierLink.contenu(caseCible)
            if len(list) == 0:
                return False
            else:
                self._competence.briseGenoux(self._elements[list[0]])
                return True
        
        if (self._prochaineAction == "Ressucite"):
            list = self._damierLink.contenu(caseCible)
            if len(list) == 0:
                return False
            cible = self._elements[list[0]]
            if cible.pointDeVie > 0:
                print "On ne peut ressuciter les vivants"
                return False
            else:
                self._competence.ressucite(cible)
                self.prochainTourPersonnage(cible)
                return True
        
        
        raise Exception(self._prochaineAction + " n'est pas implémenté")

    def calculOrdreInitialDeJeu(self):
        '''
        cette fonction permet d'initialiser le dictionnaire _deroulement
        à partir de l'initiative des différents personnages    
        '''
        for nom in self._elements: 
            if isinstance(self._elements[nom], Personnage):
                self._calculOrdreDeJeu(self._elements[nom])
  
    def casesCiblesDisponibles(self):
        return self._choice
 
    def competenceActive(self):
        return self._competenceActive

    def prochaineAction(self):
        return self._prochaineAction
  
    def prochainTour(self, gameStatus):
        # on récupère la liste trié des timeKeys
        timeKeys = self._deroulement.keys() 
        timeKeys.sort()
        
        # initialisation des attributs
        self._tour = timeKeys[0]
        nextPerso = self._elements[self._deroulement[self._tour][0][0]]
        
        # on retire le premier élément pour l'inclure dans GameStatus._tour
        firstActionTuple = self._deroulement[self._tour].pop(0)
        gameStatus.maj_tour("Joueur "
                            + str(nextPerso.joueur)
                            + ' : '
                            + firstActionTuple[0] )
    
        # on inclue les autres dans gameStatus.activite
        texte = ""
        for timeKey in timeKeys:
            for actionTuple in self._deroulement[timeKey]:
                if timeKey > 10:
                    texte += str(timeKey)[0:4]
                else:
                    texte += str(timeKey)[0:3]
                    
                texte += ") "           \
                    + "Joueur"          \
                    + str(self._elements[actionTuple[0]].joueur) \
                    + " : "             \
                    + (actionTuple[0])  \
                    + ("\n  ")          \
                    + (actionTuple[1])  \
                    + ("\n\n\n")
        gameStatus.maj_activite(texte)
        
        self._nettoieDeroulement()
        
        self._choice = None
        self._competenceActive = 0
        self._prochaineAction = ""
        
        return nextPerso
   
    def prochainTourPersonnage(self, personnage):
        '''
            Permet de calculer le prochain _tour de jeu du personnage
        qui vient de choisir son action.
        '''
        self._calculOrdreDeJeu(personnage)
    

    def _demandeRessucite(self, personnage):
        distance = 2
        case = self._damierLink.donnePosition(personnage.nom)
        self._choice = self._casePossible(distance, case)
        self._competenceActive = 1
        self._prochaineAction = "Ressucite"
        return self._choice, "marque_choixPossible"

    def _demandePasseTour(self, competence):
        self._competenceActive = 1
        self._prochaineAction = competence
        return competence
    
    def _demandeMouvement(self, personnage):
        '''
        l'activité regarde la compétence mouvement du personnage
        et rend la liste des cases choisissables pour effectuer un mouvement
        '''
        distance = personnage.mouvement()
        case = self._damierLink.donnePosition(personnage.nom)
        self._choice = self._casePossible(distance, case)

        list = []
        for case in self._choice:
            if self._elements[case].franchissable == False:
                list.append(case)
            for element in self._damierLink.contenu(case):
                if self._elements[element].franchissable == False:
                    list.append(case)
        
        for case in list:
            if case in self._choice:
                self._choice.remove(case)
        
        
        self._competenceActive = True
        self._prochaineAction = "Mouvement"
        return self._choice, "marque_choixPossible"

    def _demandeTir(self, personnage):
        '''
        '''
        distance = (int) (personnage.constitution*0.8)
        case = self._damierLink.donnePosition(personnage.nom)
        self._choice = self._casePossible(distance, case)
        self._competenceActive = True
        self._prochaineAction = "Tir"
        return self._choice, "marque_choixPossible"
        
    def _demandeFrappe(self, personnage):
        distance = 1
        case = self._damierLink.donnePosition(personnage.nom)
        self._choice = self._casePossible(distance, case)
        self._competenceActive = 1
        self._prochaineAction = "Frappe"
        return self._choice, "marque_choixPossible"

    def _demandeShadowBolt(self, personnage):
        distance = (int) (personnage.constitution*0.8)
        case = self._damierLink.donnePosition(personnage.nom)
        self._choice = self._casePossible(distance, case)
        self._competenceActive = 1
        self._prochaineAction = "Shadow Bolt"
        return self._choice, "marque_choixPossible"

    def _demandeSeduction(self, personnage):
        distance = 1
        case = self._damierLink.donnePosition(personnage.nom)
        self._choice = self._casePossible(distance, case)
        self._competenceActive = 1
        self._prochaineAction = "Seduction"
        return self._choice, "marque_choixPossible"

    def _demandeBriseGenoux(self, personnage):
        distance = 1
        case = self._damierLink.donnePosition(personnage.nom)
        self._choice = self._casePossible(distance, case)
        self._competenceActive = 1
        self._prochaineAction = "Brise Genoux"
        return self._choice, "marque_choixPossible"

    def _demandeSoin(self, personnage):
        distance = 5
        case = self._damierLink.donnePosition(personnage.nom)
        self._choice = self._casePossible(distance, case)
        self._competenceActive = 1
        self._prochaineAction = "Soigne"
        return self._choice, "marque_choixPossible"
    
    def _casePossible(self, mouvement, caseRef):
        '''
        recherche le nom des cases correspondant à une distance maximum
        d'une case référence
        '''
        x,y = ord(caseRef[0]), int(caseRef[1])
        list = []
        for i in range(0, mouvement + 1):
            for j in range(0, mouvement +1):
                if i+j > mouvement or i+j == 0: continue
    
                case = chr(x + i) + str(y + j)
                if case not in list\
                    and case in self._damierLink._position.keys() :
                    list.append(case)
                
                case = chr(x + i) + str(y - j)
                if case not in list\
                    and case in self._damierLink._position.keys() :
                    list.append(case)
                
                case = chr(x - i) + str(y + j)
                if case not in list\
                    and case in self._damierLink._position.keys() :
                    list.append(case)
                
                case = chr(x - i) + str(y - j)
                if case not in list\
                    and case in self._damierLink._position.keys() :
                    list.append(case)

        return list
            
    def _calculOrdreDeJeu(self, personnage):
        timeKey = self._competence.momentDeJeu(personnage.initiative())
        timeKey += self._tour
        actionTuple = (personnage.nom, 'tourDeJeu', None)
        if self._deroulement.has_key(timeKey):
            self._deroulement[timeKey].append(actionTuple)
        else:
            self._deroulement[timeKey] = [actionTuple]
    
        self._retireActionDesMorts()
        self._nettoieDeroulement()
        
    def _nettoieDeroulement(self):
        for (timeKey, actionTuples) in self._deroulement.items():
            if actionTuples == []:
                del self._deroulement[timeKey]

    def _retireActionDesMorts(self):
        for (timeKey, actionTuples) in self._deroulement.items():
            for actionTuple in actionTuples:
                if self._elements[actionTuple[0]].mort():
                    self._deroulement[timeKey].remove(actionTuple)

    